package com.cloudfast.manager.impl;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import com.cloudfast.config.property.c.DefaultProperty;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import com.cloudfast.channel.SFTPChannel;
import com.cloudfast.manager.FileStorageManager;
import com.cloudfast.response.FileResponse;
import com.cloudfast.utils.FileUtils;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.SftpException;

/**
 * sftp 文件操作类
 *
 * @author liuyw
 */
public class SftpStorageManagerImpl extends BaseManagerImpl implements FileStorageManager {

    private static final Logger logger = LoggerFactory.getLogger(Logger.class);

    private DefaultProperty defaultProperty;

    public SftpStorageManagerImpl(DefaultProperty defaultProperty, int maxFileSize) {
        this.defaultProperty = defaultProperty;
        this.maxFileSize = maxFileSize;
    }

    @Override
    public FileResponse upload(MultipartFile file) {
        return upload(file, null);
    }

    @Override
    public FileResponse upload(MultipartFile file, String prefix) {

        // 文件不能为空
        if (file == null || file.isEmpty()) {
            throw new RuntimeException("文件不能为空");
        }

        // 不能超过最大支持
        if (file.getSize() > maxFileSize) {
            throw new RuntimeException("文件太大,已超出最大支持范围:" + maxFileSize);
        }
        // 获取文件名称
        String originalName = file.getOriginalFilename();
        // 获取后缀名称
        String suffix = FileUtils.getFilenameSuffix(originalName);
        // 获取需要保存的文件名称
        String radomName = FileUtils.getRadomName() + "." + suffix;

        // 获取文件保存的路径
        String storageFilePath = "/" + FileUtils.getYmdPath() + "/";
        if (StringUtils.isNotEmpty(prefix)) {
            storageFilePath = "/" + prefix + "/" + FileUtils.getYmdPath() + "/";
        }

        FileResponse fileResponse = null;
        try {
            fileResponse = upload(file.getInputStream(), storageFilePath, radomName);
            if (fileResponse != null) {
                fileResponse.setOriginalName(originalName);
                fileResponse.setFileSize(file.getSize());
                fileResponse.setBrowser(defaultProperty.getBrowserPrefix() + storageFilePath + radomName);
            }
        } catch (IOException e) {
            throw new RuntimeException("读取文件流失败.");
        }

        return fileResponse;
    }

    @Override
    public FileResponse upload(InputStream stream, String filePath, String fileName) {
        SFTPChannel channel = new SFTPChannel();
        ChannelSftp chSftp;
        try {
            chSftp = channel.getChannel(this.defaultProperty, 60000);
            String storagePath = this.defaultProperty.serverStoragePath(filePath);
            // 切入文件存储路径
            this.changeFolder(chSftp, storagePath);
            // 保存文件
            chSftp.put(stream, fileName, ChannelSftp.OVERWRITE);
            // 退出sftp
            chSftp.quit();
            // 关闭sftp
            channel.closeChannel();
        } catch (JSchException jse) {
            channel.closeChannel();
            throw new RuntimeException("连接ftp服务，通道开启失败。");
        } catch (SftpException se) {
            channel.closeChannel();
            throw new RuntimeException("已连接ftp服务，附件上传失败。");
        } catch (Exception e) {
            channel.closeChannel();
            throw new RuntimeException(e.getMessage());
        } finally {
            try {
                stream.close();
            } catch (IOException e) {
                logger.error(e.getMessage());
            }
            channel.closeChannel();
        }
        return new FileResponse("", (filePath + "/" + fileName).replaceAll("//", "/"), fileName,
                fileName.split("\\.")[1], 0, "");
    }

    @Override
    public byte[] download(String filePath) {
        SFTPChannel channel = new SFTPChannel();
        ChannelSftp chSftp = null;
        try {
            chSftp = channel.getChannel(this.defaultProperty, 60000);
            InputStream in = chSftp.get(this.defaultProperty.serverStoragePath(filePath));
            return IOUtils.toByteArray(in);
        } catch (JSchException jse) {
            channel.closeChannel();
            throw new RuntimeException("连接ftp服务，通道开启失败。");
        } catch (SftpException se) {
            channel.closeChannel();
            se.printStackTrace();
            throw new RuntimeException("已连接ftp服务，附件下载失败。");
        } catch (IOException e) {
            channel.closeChannel();
            throw new RuntimeException("文件已写入请求，IO流关闭失败。");
        } finally {
            if (chSftp != null) {
                chSftp.quit();
            }
            channel.closeChannel();
        }
    }

    /**
     * <p>
     * 切换至服务器文件存储路径
     * </p>
     *
     * @param chSftp   通道对象
     * @param filePath 文件路径
     */
    private void changeFolder(ChannelSftp chSftp, String filePath) {
        String[] dirs = filePath.split("/");
        StringBuilder path = new StringBuilder();
        for (String dir : dirs) {
            path.append(dir).append("/");
            try {
                chSftp.cd(path.toString());
            } catch (SftpException sException) {
                if (ChannelSftp.SSH_FX_NO_SUCH_FILE == sException.id) {
                    try {
                        chSftp.mkdir(path.toString());
                        chSftp.cd(path.toString());
                    } catch (SftpException e) {
                        throw new RuntimeException(e.getMessage());
                    }
                }
            }
        }
    }

    @Override
    public int deleteFile(String filePath) {
        SFTPChannel channel = new SFTPChannel();
        ChannelSftp chSftp = null;
        try {
            // 路径不为空
            if (StringUtils.isNotEmpty(filePath)) {
                String[] files = filePath.split(",");
                for (int i = 0; i < files.length; i++) {
                    chSftp = channel.getChannel(this.defaultProperty, 60000);
                    chSftp.rm(defaultProperty.serverStoragePath(files[i]));
                    channel.closeChannel();
                }
                return 1;
            }
        } catch (JSchException | SftpException e) {
            throw new RuntimeException("删除文件失败");
        } finally {
            if (chSftp != null) {
                chSftp.quit();
            }
            channel.closeChannel();
        }
        return 0;
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<File> iterationFile(String rootPath) {
        SFTPChannel channel = new SFTPChannel();
        ChannelSftp chSftp = null;
        List<File> fileList = new ArrayList<File>();
        try {
            String storagePath = this.defaultProperty.serverStoragePath(rootPath);
            chSftp = channel.getChannel(this.defaultProperty, 60000);
            // 切入文件存储路径
            this.changeFolder(chSftp, storagePath);
            Vector<ChannelSftp.LsEntry> vector = chSftp.ls(storagePath);
            for (ChannelSftp.LsEntry item : vector) {
                if (!item.getAttrs().isDir()) {
                    fileList.add(new File(item.getFilename()));
                }
            }
        } catch (JSchException | SftpException e) {
            throw new RuntimeException("遍历失败");
        } finally {
            if (chSftp != null) {
                chSftp.quit();
            }
            channel.closeChannel();
        }

        return fileList;
    }

}
